package com.ctshk.rpc.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.SystemBusinessType;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.utils.DateUtil;
import com.ctshk.rpc.system.req.UploadReq;
import com.ctshk.rpc.system.service.IFileOSSService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;

import java.io.*;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * 阿里云OSS文件服务
 * </p>
 *
 * @author 胡广
 * @since 2021/3/1
 */
@Slf4j
@DubboService
@RefreshScope
public class FileOSSServiceImpl implements IFileOSSService {
    // Endpoint以杭州为例，其它Region请按实际情况填写。
//    private  String endpoint = "https://ctshk-cloud-dev.oss-cn-hongkong.aliyuncs.com";
    @Value("${oss.service.endpoint}")
    private String endpoint;
    // 阿里云主账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维，请登录RAM控制台创建RAM账号。
    @Value("${oss.service.accessKeyId}")
    private String accessKeyId;
    @Value("${oss.service.accessKeySecret}")
    private String accessKeySecret;
    @Value("${oss.service.bucketName}")
    private String bucketName;
    @Value("${oss.service.domain}")
    private String domain;
    @Value("${oss.service.preUrl}")
    private String preUrl;

    public static final String SCENIC_IMG_SPACE = "scenic-img-space";

    @Override
    public void createBucketByName(String bucketName) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        boolean b = ossClient.doesBucketExist(bucketName);
        if (!b) {
            ossClient.createBucket(bucketName);
        }
        ossClient.shutdown();
    }

    @Override
    public void createBucket() {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 创建存储空间。FileOSSServiceImpl
        ossClient.createBucket(bucketName);

        // 关闭OSSClient。
        ossClient.shutdown();
    }

    @Override
    public Result upload(String fileName, byte[] bytes, int businessType) {
        // <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径，例如abc/efg/123.jpg。
        log.info("【OSS文件服务-上传文件】上传文件:{},业务类型:{}", fileName, businessType);
        String name = SystemBusinessType.parseName(businessType);
        if (name == null) {
            // 业务类型不存在
            return Result.failed(SystemError.SYS_500);
        }
        String suffix = fileName.substring(fileName.indexOf("."));
        String fullPath = name + "/" + DateUtil.fmt(LocalDateTime.now(), "yyMMdd") + "/" + UUID.randomUUID().toString().replace("-","") + suffix;
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        if (!ossClient.doesBucketExist(bucketName)) {
            log.info("【OSS文件服务-上传文件】您的Bucket不存在，创建Bucket：{}", bucketName);
            // 创建Bucket。详细请参看“SDK手册 > Java-SDK > 管理Bucket”。
            // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/manage_bucket.html?spm=5176.docoss/sdk/java-sdk/init
            ossClient.createBucket(bucketName);
        }
        // 上传文件到指定的存储空间（bucketName）并将其保存为指定的文件名称（objectName）。
        try {
            PutObjectResult putObjectResult = ossClient.putObject(bucketName, fullPath, new ByteArrayInputStream(bytes));
            log.info("【OSS文件服务-上传文件】上传文件成功，putObjectResult：{}", JSON.toJSONString(putObjectResult));
            return Result.success(preUrl + fullPath);
        } catch (Exception e) {
            log.error("【OSS文件服务-上传文件】上传文件异常，error：{}", e.getMessage(), e);
            return Result.failed(SystemError.SYS_427);
        } finally {
            // 关闭OSSClient。
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    @Override
    public Result uploadBatch(List<UploadReq> uploadReqList) {
        if (CollectionUtils.isNotEmpty(uploadReqList)) {
            String[] excludeProperties = {"bytes"};
            PropertyPreFilters filters = new PropertyPreFilters();
            PropertyPreFilters.MySimplePropertyPreFilter excludeFilter = filters.addFilter();
            excludeFilter.addExcludes(excludeProperties);
            log.info("【OSS文件服务-批量上传文件】上传文件,files:{}", JSON.toJSONString(uploadReqList, excludeFilter));
            OSS ossClient = null;
            try {
                // 创建OSSClient实例。
                ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
                log.info("【OSS文件服务-批量上传文件】获取OSS实例");
                if (!ossClient.doesBucketExist(bucketName)) {
                    log.info("【OSS文件服务-批量上传文件】您的Bucket不存在，创建Bucket：{}。", bucketName);
                    // 创建Bucket。详细请参看“SDK手册 > Java-SDK > 管理Bucket”。
                    // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/manage_bucket.html?spm=5176.docoss/sdk/java-sdk/init
                    ossClient.createBucket(bucketName);
                }
                for (UploadReq uploadReq : uploadReqList) {
                    // https://ctshk-cloud-dev.oss-cn-hongkong.aliyuncs.com/fileName
                    // 上传文件到指定的存储空间（bucketName）并将其保存为指定的文件名称（objectName）。
                    String fullName = uploadReq.getFullName();
                    byte[] bytes = uploadReq.getBytes();
                    PutObjectResult putObjectResult = ossClient.putObject(bucketName, fullName, new ByteArrayInputStream(bytes));
                    log.info("【OSS文件服务-批量上传文件】上传文件成功, putObjectResult:{}", JSON.toJSONString(putObjectResult));
                }
            } catch (Exception e) {
                log.error("【文件OSS服务-批量上传文件】上传文件异常, error:{}", e.getMessage(), e);
                return Result.failed(SystemError.SYS_427);
            } finally {
                if (ossClient != null) {
                    // 关闭OSSClient。
                    ossClient.shutdown();
                }
            }
        }
        return Result.success();
    }

    @Override
    public byte[] download(String objectName) {
        // <yourObjectName>从OSS下载文件时需要指定包含文件后缀在内的完整路径，例如abc/efg/123.jpg。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 调用ossClient.getObject返回一个OSSObject实例，该实例包含文件内容及文件元信息。
        OSSObject ossObject = ossClient.getObject(bucketName, objectName);
        // 调用ossObject.getObjectContent获取文件输入流，可读取此输入流获取其内容。
        InputStream inputStream = ossObject.getObjectContent();
        if (inputStream != null) {
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024 * 4];
            int len = 0;
            try {
                while (-1 != (len = inputStream.read(buffer))) {
                    output.write(buffer, 0, len);
                }
                inputStream.close();
            } catch (IOException e) {
                try {
                    output.close();
                    inputStream.close();
                } catch (IOException ioException) {
                    log.error("【文件OSS服务-下载文件】下载文件异常，关闭流异常， exception:{}", ioException);
                }
            }
            return output.toByteArray();
        }
        // 关闭OSSClient。
        ossClient.shutdown();
        return new byte[0];
    }

    @Override
    public Result findObject(String objectName) {
        // <yourObjectName>从OSS下载文件时需要指定包含文件后缀在内的完整路径，例如abc/efg/123.jpg。
        // 创建OSSClient实例。
//        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 调用ossClient.getObject返回一个OSSObject实例，该实例包含文件内容及文件元信息。
        OSSObject ossObject = null;
        try {
            ossObject = ossClient.getObject(bucketName, objectName);
            log.info("【OSS文件服务】查询Object,ossObject:{}", JSON.toJSONString(ossObject));
        } catch (OSSException ossException) {
            log.error("【OSS文件服务】getObject error, oss exception:{}", JSON.toJSONString(ossException));
//            if (ossException.getErrorCode().equals("NoSuchKey")) {
//                return Result.failed(SystemError.SYS_426);
//            }
            return Result.failed(SystemError.SYS_425);
        } catch (Exception exception) {
            log.error("【OSS文件服务】getObject error, exception:{}", JSON.toJSONString(exception));
            return Result.failed(SystemError.SYS_425);
        }
        // 调用ossObject.getObjectContent获取文件输入流，可读取此输入流获取其内容。
        InputStream inputStream = ossObject.getObjectContent();
        if (inputStream == null) {
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024 * 4];
            int len = 0;
            try {
                while (-1 != (len = inputStream.read(buffer))) {
                    output.write(buffer, 0, len);
                }
                inputStream.close();
                ossClient.shutdown();
                return Result.success(output.toByteArray());
            } catch (IOException e) {
                try {
                    inputStream.close();
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            }
        }
        // 关闭OSSClient。
        ossClient.shutdown();
        return Result.failed(SystemError.SYS_425);
    }

    @Override
    public void list() {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // ossClient.listObjects返回ObjectListing实例，包含此次listObject请求的返回结果。
        ObjectListing objectListing = ossClient.listObjects(bucketName);
        // objectListing.getObjectSummaries获取所有文件的描述信息。
        for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
            log.info("【OSS文件服务】 - " + objectSummary.getKey() + "  " +
                    "(size = " + objectSummary.getSize() + ")");
        }

        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * 正式上传图片文件，并返回获取文件绝对路径
     *
     * @param bucketName 空间名
     * @param is
     * @param fileName   文件名
     * @return
     */
    @Override
    public String uploadFile2OSS(String bucketName, InputStream is, String fileName) {
        String ret = "";
        try {
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(is.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType("image/*");
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            ossClient.putObject(bucketName, fileName, is, objectMetadata);
            ossClient.shutdown();
            //组合访问绝对路径，此种直接访问方式需要打开OSS的跨域设置，此外此部访问文式存在倒链问题，需要在OSS安全设置中设置哪些网站能够访问。
            //https://scenic-img-space.oss-cn-hongkong.aliyuncs.com/000485aa-26b6-4d7f-aba2-dce6e7606614.jpg
            ret = "https://" + bucketName + ".oss-cn-hongkong.aliyuncs.com/" + fileName;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    public static void main(String[] arges) throws Exception {
        File file = new File("C:\\Users\\root\\Downloads\\logo.png");
        FileInputStream fis = new FileInputStream(file);
        /*String ref = new FileOSSServiceImpl().uploadFile2OSS(bucketName, fis,"logo.png");
        System.out.println(ref);*/
    }
}
